import { particleShader } from '../core/shader'


// INTRO ANIMATION
export default function mixinIntro(Incident) {
  var tmpV2 = new THREE.Vector3();
  var tmpV = new THREE.Vector3();
  var xorgen = new xor4096('heabllo.');
  var loaderXorgen = new xor4096('alflog.');
  var objectXorgen = new xor4096('hello.');

  function getIntroColors () {
    // 颜色值
    var introColors = [0xFCEE21, 0x009245, 0xF7931E, 0x006837, 0xFBB03B, 0xFFFFFF, 0x0071BC, 0xD9E021, 0x22B573, 0x8CC63F, 0x00A99D, 0x29ABE2];

    return introColors.map(function(c) { return new THREE.Color(c); });
  }

  function intersect(c, cs) {
    var x0a = c.start.position.x;
    var y0a = c.start.position.y;
    var x1a = c.end.position.x;
    var y1a = c.end.position.y;

    var k_a = (y1a - y0a) / (x1a - x0a);
    var b_a = y0a - k_a * x0a;

    for (var i = 0; i < cs.length; i++) {
      var d = cs[i];

      var x0b = d.start.position.x;
      var y0b = d.start.position.y;
      var x1b = d.end.position.x;
      var y1b = d.end.position.y;

      var k_b = (y1b - y0b) / (x1b - x0b);
      var b_b = y0b - k_b * x0b;

      if (k_a === k_b) {
        continue;
      }

      if (c.start.position === d.start.position && tmpV.subVectors(d.end, d.start).dot(tmpV2.subVectors(c.end, c.start)) > 0.8) {
        return true;
      }

      // k_a * x + b_a = k_b * x + b_b
      // x * (k_a - k_b) + b_a - b_b = 0
      var x = (b_b - b_a) / (k_a - k_b);

      if (x > Math.min(x0a, x1a) && x > Math.min(x0b, x1b) && x < Math.max(x0a, x1a) && x < Math.max(x0b, x1b)) {
        return true;
      }

    }
    return false;
  }

  function gridKey(x,y) {
    return Math.floor(x*5) + ':' + Math.floor(y*5);
  }

  function angleDist(x, y) {
    return Math.atan2(Math.sin(x-y), Math.cos(x-y))
  }

  // 创建粒子
   Incident.prototype.makeBlob = function(color, idx) {
    var mat = this.canvasShaderMaterial.clone();

    mat.uniforms = {
      map: {type: 't', value: this.blobTextures[idx]},
      color: {type: 'v3', value: new THREE.Vector3(color.r, color.g, color.b)}
    };

    var blob = new THREE.Mesh(
      this.itemGeometry, mat
    );

    blob.texId = idx;

    return blob;
  };


   // 简介
  Incident.prototype.initIntro = function() {
    var self = this
    var introColors = getIntroColors()
    // 收缩定位
    var shrinkPositions = [];


    // 简介 粒子
    this.introBlobs = new THREE.Object3D();
    // 当这个### 属性被设置的时候，它将在渲染物体之前，检查每一帧的物体是否在摄像机的视锥体中。
    // 否则，即使该物体不可见，它也将在每一帧中被渲染，默认值为true。
    this.introBlobs.frustumCulled = false;
    // 添加道场景中
    this.scene.add(this.introBlobs);

    this.loaderBlobs = new THREE.Object3D();
    this.loaderBlobs.frustumCulled = false;
    this.introBlobs.add(this.loaderBlobs);

    // 创建 10 个 粒子
    for (var i = 0; i < 10; i++) {
      var color = introColors[i % introColors.length];
      var blob = this.makeBlob(color, i % this.blobTextures.length);
      // 三速
      blob.velocity = new THREE.Vector3();
      // 缩放速度
      blob.scaleSpeed = 0;
      // 目标 比例
      blob.targetScale = 0.001;
      // 正常 比例
      blob.normalScale = 5 * (0.2 + loaderXorgen()*0.35);
      // 是否可见
      blob.visible = false;
      // 添加
      this.loaderBlobs.add(blob);
      // 非可视区域不可见
      blob.frustumCulled = false;
      // 根据目标比例进行变化，
      blob.scale.multiplyScalar(blob.targetScale);
      // 目标位置抖动
      blob.position.set(loaderXorgen()-0.5, loaderXorgen()-0.5, loaderXorgen()*0.1+0.1).multiplyScalar(10);
    }

    var tmpV2 = new THREE.Vector3();
    this.loaderBlobs.tick = function() {
      var t = Date.now();


      console.log('loaderBlobs => ', this.loaderBlobs)
      for (var i=0; i < this.children.length; i++) {
        var a = this.children[i];

        // 下载的百分比  percentage：百分比
        if (i * 9 < $scope.loadingPercentage - 10) {
          a.targetScale = a.normalScale;
          a.visible = true;
        }

        a.violence = true;

        if (self.$camera.introTime > 350) {
          a.targetScale = shrinkPositions[i].scale * (1.5 + 0.5 * Math.sin(i*1.3+Math.pow(self.$camera.introTime/350, 2)));
          if (self.$camera.introTime > 2750 && self.$camera.introTime < 3000) {
            a.targetScale *= 1.8;
          }
        } else {
          a.targetScale = shrinkPositions[i].scale * 2.0;
          a.position.z = 0.1 + i*0.1;
        }

        // if (!a.exit) {
        a.velocity.x += (self.$camera.introTime+200)*0.0001 * (loaderXorgen() - 0.5) * 0.5;
        a.velocity.y += (self.$camera.introTime+200)*0.0001 * (loaderXorgen() - 0.5) * 0.5;
        a.velocity.z = 0;
        // }

        if (!a.visible) continue;

        var sx = a.scale.x;
        a.scaleSpeed += (a.targetScale - sx) * (a.violence ? 0.05 : 0.01);
        sx += a.scaleSpeed;
        a.scaleSpeed *= (a.violence ? 0.5 : 0.9);
        a.scale.set(sx, sx, sx);

        if (self.$camera.introTime < 350 && false) {
          a.velocity.add(tmpV2.copy(a.position).multiplyScalar(a.violence ? -0.05 : -0.005));
        } else if (self.$camera.introTime > 3000) {
          if (!a.exit) {
            a.exit = true;
            a.velocity.set(loaderXorgen()-0.5, loaderXorgen()-0.5, 0);
            a.velocity.normalize().multiplyScalar(10);
          }
        } else {
          tmpV.copy(shrinkPositions[i].position).multiplyScalar(self.$camera.introTime > 350 ? 1 : 1.8);
          a.velocity.add(tmpV2.subVectors(a.position, tmpV).multiplyScalar(self.$camera.introTime > 350 ? -0.25 : -0.005));
          a.velocity.multiplyScalar(0.9);
        }
      }

      for (var i = 0; i < this.children.length; i++) {
        var a = this.children[i];
        if (!a.visible) continue;

        /* if (false && loaderXorgen() < 0.02 && self.introTime < 350) {
          a.velocity.x += (loaderXorgen() - 0.5);
          a.velocity.y += 0.5*(loaderXorgen() - 0.5);
        } */

        a.position.add(a.velocity);
        a.position.z = i/100;

        if (a.exit) continue;

        a.velocity.multiplyScalar(0.95);
      }
    };

    // console.time('intro blob generation');

    var v = new THREE.Vector3();
    var ratio = (window.innerWidth / window.innerHeight);
    var positionGrid = {};
    var positions = [];
    var fast = !(/Android|mobile|Trident|Edge/i).test(navigator.userAgent);
    var blobCount = fast ? 12000 : 1000;
    var blobSeparation = (blobCount < 8000 ? 1.9 : 0.8)*ratio;

    for (var j = 0; j < blobCount; j++) {
      var position = new THREE.Vector3();
      var scale = 1 * (xorgen() * 0.75 + 0.2);
      var a = xorgen() * Math.PI * 2;

      if (ratio > 1) {
        v.set(Math.cos(a), Math.sin(a) / ratio, 0);
      } else {
        v.set(Math.cos(a) * ratio, Math.sin(a), 0);
      }

      var minDist = 0;
      var len = blobSeparation * Math.sqrt(j / Math.PI);
      position.copy(v);
      position.multiplyScalar(len);
      while (positionGrid[gridKey(position.x, position.y)]) {
        position.copy(v);
        len += scale;
        position.multiplyScalar( len );
      }
      positionGrid[gridKey(position.x, position.y)] = true;
      positions.push({ position: position, scale: scale, color: introColors[j % introColors.length] });
    }

    // console.timeEnd('intro blob generation');

    for (var j = 0; j < 10; j++) {
      var position = new THREE.Vector3();
      var scale = 3.5*(loaderXorgen()*0.15 + 0.1);
      var a = 2*j/9.1213*Math.PI*2;
      v.set(Math.cos(a), Math.sin(a), 0);
      var minDist = 0;
      var len = 0;
      position.copy(v);
      position.multiplyScalar(len);

      while (minDist === 0.0) {
        minDist = 10000.0;
        for (var i=0; i<shrinkPositions.length; i++) {
          var p = shrinkPositions[i];
          var dist = position.distanceTo(p.position);

          dist -= 0.5*scale;
          dist -= 0.5*p.scale;

          if (dist < minDist) {
            minDist = dist;
          }

          while (dist < 0.1) {
            position.copy(v);
            len += 0.1;
            position.multiplyScalar( len );
            var dist = position.distanceTo(p.position);
            dist -= 0.5*scale;
            dist -= 0.5*p.scale;
          }
        }
      }

      shrinkPositions.push({ position: position, scale: scale, color: introColors[j % introColors.length] });
      this.loaderBlobs.children[j].position.copy(position).normalize().multiplyScalar(2.5);
    }

    // 扩大
    // 开时，扩大后的连接线
    var growTree = function(start, positions, angle, connections, depth) {
      var previousConnection = null;

      var closePositions = positions.filter(function(p) {
        var len = p.position.distanceTo(start.position);
        return len > 1 && len < 10;
      });

      for (var i=0; i<5; i++) {
        var a = angle + i/5 * Math.PI * 2;
        var angleVec = new THREE.Vector3(Math.cos(a), Math.sin(a), 0).normalize();
        var connection = {};
        connection.start = start;
        var tries = 0;
        var len, dot;
        // debugger;
        var match = null;

        for (var j=0; j<closePositions.length; j++) {
          var p = closePositions[j];
          connection.end = p;
          tmpV2.subVectors(connection.end.position, connection.start.position).normalize();
          dot = tmpV2.dot(angleVec);
          if (dot < 0.5 && !intersect(connection, connections)) {
            match = p;
            break;
          }
        }

        if (match) {
          connection.end = match;
          connections.push(connection);
          if (previousConnection ) {
            var cline = {start: previousConnection.end, end: connection.end};
            if (!intersect(cline, connections)) {
              connections.push(cline);
            }
          }
          if (depth < 2) {
            growTree(connection.end, positions, angle, connections, depth+1);
          }
          previousConnection = connection;
        }
      }

      return connections;
    };


    // console.time('connection generation');

    var introBlobConnections = new THREE.Object3D();
    introBlobConnections.position.z = 0.1;
    var connections = [];
    var tmpV = new THREE.Vector3();
    var angleVec = new THREE.Vector3();
    var angle = 0;


    var connectionPathCount = fast ? 15 : 5;
    for (var i=0; i<connectionPathCount; i++) {
      var idx = i+(15*(Math.pow(Math.random(), 2-i/15)*positions.length/15) | 0);
      idx %= positions.length;
      var start = positions[idx];
      start.finishedGrowing = true;

      growTree(start, positions.filter(function(p){
        var a = Math.atan2(p.position.y, p.position.x);
        return p.color === start.color && Math.abs(angleDist(a, angle)) < Math.PI*2/3;
      }), angle, connections, 0);

      angle += Math.PI * (2 / 3 + (xorgen()-0.5) );
    }

    for (var i=0; i<connections.length; i++) {
      var geo = new THREE.Geometry();
      geo.vertices.push(new THREE.Vector3(0,0,0));
      geo.vertices.push(new THREE.Vector3().subVectors(connections[i].end.position, connections[i].start.position));
      var color = new THREE.Color(connections[i].end.color);
      color.r = Math.min(1, color.r + 0.2);
      color.g = Math.min(1, color.g + 0.2);
      color.b = Math.min(1, color.b + 0.2);
      var line = new THREE.Line(geo, new THREE.LineBasicMaterial({linewidth: 1, color: color}));
      line.position.copy(connections[i].start.position);
      line.scale.set(0.001, 0.001, 0.001);
      line.targetScale = 0.001;
      line.visible = false;
      line.delay = 10 + i/10 + Math.pow(xorgen(), 2) * 250;
      introBlobConnections.add(line);
    }

    // console.timeEnd('connection generation');

    introBlobConnections.tick = function() {
      for (var i=0; i<this.children.length; i++) {
        var c = this.children[i];
        if (connections[i].start.visible && connections[i].end.visible && connections[i].start.finishedGrowing) {
          c.targetScale = 1;
          c.visible = true;
        } else {
          c.targetScale = 0.001;
        }

        if (c.delay > 0) {
          c.delay--;
          continue;
        }

        var sx = c.scale.x;
        sx += (c.targetScale - sx) * 0.2;
        c.scale.set(sx, sx, sx);
        connections[i].end.finishedGrowing = true;

        if (sx > 0.95) {
        } else if (sx < 0.01) {
          c.visible = false;
        }
      }
    };

    this.introBlobs.add(introBlobConnections);

    // 粒子 着色器
    var particleShader =  particleShader

    // 创建粒子
    this.introBlobs.createBlobs = function() {
      var blobs = new THREE.Object3D();
      var particleGeo = new THREE.BufferGeometry();
      this.particlePositions = new Float32Array(6 * 3 * positions.length);
      this.particleScales = new Float32Array(6 * 1 * positions.length);
      this.particleColors = new Float32Array(6 * 3 * positions.length);
      // this.particleTextureIDs = new Float32Array(6 * 1 * positions.length);
      this.particleUVs = new Float32Array(6 * 2 * positions.length);
      particleGeo.addAttribute('position', new THREE.BufferAttribute(this.particlePositions, 3));
      particleGeo.addAttribute('scale', new THREE.BufferAttribute(this.particleScales, 1));
      particleGeo.addAttribute('color', new THREE.BufferAttribute(this.particleColors, 3));
      // particleGeo.addAttribute('textureID', new THREE.BufferAttribute(this.particleTextureIDs, 1));
      particleGeo.addAttribute('uv', new THREE.BufferAttribute(this.particleUVs, 2));

      var particleMaterial = new THREE.ShaderMaterial(particleShader);
      particleMaterial.uniforms['t'] = { type: 't', value: self.blobTextures[0] };
      // for (var i=0; i<self.blobTextures.length; i++) {
      // 	particleMaterial.uniforms['t'+i] = { type: 't', value: self.blobTextures[i] };
      // }

      // 粒子
      this.particles = new THREE.Mesh(particleGeo, particleMaterial);
      this.particles.frustumCulled = false;

      blobs.add(this.particles);
      blobs.blobControllers = [];

      for (var i=0, l=positions.length; i<l; i++) {
        var p = positions[i];
        p.visible = true;
        var blob = self.makeBlob(p.color, 0 | (xorgen() * self.blobTextures.length));
        blob.velocity = new THREE.Vector3();
        var s = p.scale;
        blob.targetScale = s;
        blob.frustumCulled = false;
        blob.scale.set(0.001, 0.001, 0.001);
        blob.position.copy(p.position).multiplyScalar(0.0);
        blob.position.z = -150*Math.random()-Math.sqrt(i/10);
        blob.floatVec = new THREE.Vector3();
        blob.positionObj = p.position;
        blobs.blobControllers.push(blob);
      }
      this.blobs = blobs;
    };

    this.introBlobs.createBlobs();

    this.introBlobs.tick = function() {
      if ($scope.introState >= 1) {
        self.loaderBlobs.tick();
      }
      if (self.$camera.introTime < 3000) return;
      if (self.$camera.introTime > self.introLength) {
        this.parent.remove(this);
      }
      if (self.$camera.introTime > 5000) {
        introBlobConnections.tick();
      }
      this.blobs.position.z += 0.03 * Math.sqrt((self.$camera.introTime-3000) / 8000);
      introBlobConnections.position.z += 0.03 * Math.sqrt((self.$camera.introTime-3000) / 8000);
      for (var i=0; i<this.blobs.blobControllers.length; i++) {
        if (!this.blobs.parent) {
          this.add(this.blobs);
        }
        var c = this.blobs.blobControllers[i];
        if (c.visible) {
          var t = Date.now()/150 + i;
          c.floatVec.set(Math.sin(1.3*t), Math.cos(t* ((i % 2) - 0.5)*2), 0);
          c.floatVec.multiplyScalar(c.bounce ? 0.35 : 0);
          c.velocity.add(c.floatVec);

          if (c.countDown) {
            c.velocity.y -= 0.1;
          } else {
            if (c.velocity.z === 0) {
              tmpV.subVectors(c.positionObj, c.position).multiplyScalar(0.125);
              c.velocity.add(tmpV);
            }
            var sx = c.scale.x;
            sx += (c.targetScale - sx) * 0.25;
            c.scale.set(sx, sx, sx);
            c.velocity.multiplyScalar(0.99);
            if (c.position.z > 0 || c.bounce) {
              c.bounce = true;
              c.velocity.multiplyScalar(0.1);
              tmpV.subVectors(c.positionObj, c.position).multiplyScalar(0.9);
              c.velocity.add(tmpV);
            }
          }
          c.position.add(c.velocity);
        } else if (i === this.blobs.blobControllers.length-1) {
          this.parent.remove(this);
        }
      }

      for (var i = 0; i < this.blobs.blobControllers.length; i++) {
        if (i < Math.pow(Math.max(0, self.$camera.introTime-11200), 1.6)) {
          if (positions[i].visible) {
            this.blobs.blobControllers[i].velocity.set((Math.random()-0.5)*8.0, Math.random(), -(6*(0.5-Math.random())));
            this.blobs.blobControllers[i].countDown = 200;
            positions[i].visible = false;
          }
        } else {
          break;
        }
      }

      var pos = this.particlePositions;
      var sca = this.particleScales;
      var col = this.particleColors;
      // var tex = this.particleTextureIDs;
      var uv = this.particleUVs;
      var off,soff,coff,toff,uoff;
      off = soff = coff = toff = uoff = 0;

      if (!this.geometryInitialized) {
        this.geometryInitialized = true;
        for (var i=0; i<this.blobs.blobControllers.length; i++) {
          var b = this.blobs.blobControllers[i];
          for (var j=0; j<6; j++) {
            col[coff++] = b.material.uniforms.color.value.x;
            col[coff++] = b.material.uniforms.color.value.y;
            col[coff++] = b.material.uniforms.color.value.z;
            // tex[toff++] = b.texId;
            uv[uoff++] = j % 2;
            uv[uoff++] = (j < 2 || j === 5) ? 0 : 1;
          }
        }
        var geo = this.particles.geometry;
        geo.attributes.color.needsUpdate = true;
        // geo.attributes.textureID.needsUpdate = true;
        geo.attributes.uv.needsUpdate = true;
      }

      for (var i=0; i<this.blobs.blobControllers.length; i++) {
        var b = this.blobs.blobControllers[i];
        for (var j=0; j<6; j++) {
          pos[off++] = b.position.x;
          pos[off++] = b.position.y;
          pos[off++] = b.position.z;
          sca[soff++] = b.scale.x;
        }
      }
      var geo = this.particles.geometry;
      geo.attributes.position.needsUpdate = true;
      geo.attributes.scale.needsUpdate = true;
    };
  };
}
